// Package scanner Apache 配置扫描器
package scanner

import (
	"bufio"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

// ApacheScanner Apache 配置扫描器
type ApacheScanner struct {
    configDirs []string // Apache 配置目录列表
}

// NewApacheScanner 创建 Apache 扫描器
func NewApacheScanner() *ApacheScanner {
	// 常见的 Apache 配置目录
	configDirs := []string{
		// CentOS/RHEL
		"/etc/httpd/conf.d",
		"/etc/httpd/sites-enabled",
		// Debian/Ubuntu
		"/etc/apache2/sites-enabled",
		"/etc/apache2/conf-enabled",
		// 其他
		"/usr/local/apache2/conf/vhosts",
		"/opt/apache2/conf/vhosts",
	}

    return &ApacheScanner{configDirs: configDirs}
}

// NewApacheScannerWithDirs 以自定义目录创建扫描器
// 允许通过 CLI/配置覆盖默认扫描目录
func NewApacheScannerWithDirs(dirs []string) *ApacheScanner {
    if len(dirs) == 0 {
        return NewApacheScanner()
    }
    return &ApacheScanner{configDirs: dirs}
}

// Scan 扫描 Apache 配置
func (s *ApacheScanner) Scan() ([]*SiteInfo, error) {
	var sites []*SiteInfo

	// 遍历所有配置目录
	for _, dir := range s.configDirs {
		// 检查目录是否存在
		if _, err := os.Stat(dir); os.IsNotExist(err) {
			continue
		}

		// 读取目录中的所有配置文件
		entries, err := os.ReadDir(dir)
		if err != nil {
			continue
		}

		for _, entry := range entries {
			if entry.IsDir() {
				continue
			}

			// 只处理 .conf 文件
			if !strings.HasSuffix(entry.Name(), ".conf") {
				continue
			}

			configPath := filepath.Join(dir, entry.Name())

			// 解析配置文件
			siteInfo, err := s.parseConfigFile(configPath)
			if err != nil {
				// 跳过解析失败的文件
				continue
			}

			if siteInfo != nil {
				sites = append(sites, siteInfo)
			}
		}
	}

	return sites, nil
}

// parseConfigFile 解析 Apache 配置文件
func (s *ApacheScanner) parseConfigFile(configPath string) (*SiteInfo, error) {
	file, err := os.Open(configPath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var (
		domains  []string
		certPath string
		keyPath  string
		inVHost  bool
		hasSSL   bool
	)

	// 正则表达式
	serverNameRe := regexp.MustCompile(`^\s*ServerName\s+(.+)`)
	serverAliasRe := regexp.MustCompile(`^\s*ServerAlias\s+(.+)`)
	sslCertRe := regexp.MustCompile(`^\s*SSLCertificateFile\s+(.+)`)
	sslKeyRe := regexp.MustCompile(`^\s*SSLCertificateKeyFile\s+(.+)`)
	vhostStartRe := regexp.MustCompile(`^\s*<VirtualHost\s+.*:443>`)

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()

		// 检测 VirtualHost 块 (SSL 端口 443)
		if vhostStartRe.MatchString(line) {
			inVHost = true
			hasSSL = true
			continue
		}

		if !inVHost {
			continue
		}

		// 检测 VirtualHost 块结束
		if strings.Contains(line, "</VirtualHost>") {
			break
		}

		// 提取 ServerName
		if matches := serverNameRe.FindStringSubmatch(line); matches != nil {
			domain := strings.TrimSpace(matches[1])
			if domain != "" && domain != "_default_" {
				domains = append(domains, domain)
			}
		}

		// 提取 ServerAlias
		if matches := serverAliasRe.FindStringSubmatch(line); matches != nil {
			aliasStr := strings.TrimSpace(matches[1])
			for _, alias := range strings.Fields(aliasStr) {
				if alias != "" {
					domains = append(domains, alias)
				}
			}
		}

		// 提取证书路径
		if matches := sslCertRe.FindStringSubmatch(line); matches != nil {
			certPath = strings.TrimSpace(matches[1])
		}

		// 提取私钥路径
		if matches := sslKeyRe.FindStringSubmatch(line); matches != nil {
			keyPath = strings.TrimSpace(matches[1])
		}
	}

	// 只处理 SSL 站点
	if !hasSSL || len(domains) == 0 || certPath == "" || keyPath == "" {
		return nil, nil
	}

	// 使用第一个域名作为站点名称
	siteName := domains[0]

	// 尝试读取证书信息
	var expiry time.Time
	var serial string
	var subject string

	if _, err := os.Stat(certPath); err == nil {
		expiry, serial, subject, _ = parseCertificate(certPath)
	}

	return &SiteInfo{
		Name:          siteName,
		Domains:       domains,
		ConfigFile:    configPath,
		CertPath:      certPath,
		KeyPath:       keyPath,
		CurrentExpiry: expiry,
		CertSerial:    serial,
		CertSubject:   subject,
	}, nil
}
